/*
 * Copyright (c) 2018-2024 北京华恒盛世科技有限公司
 * QUICKPOOL is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
*/

#include "subcmd.h"

static void movejob_usage(const char *);

/**
 * @brief       qp job top/bot handler, to move job to a new position.
 *
 * @param[in]   argc          #1: number of input argument
 * @param[in]   argv          #2: string array of the input argument
 *
 * @retval      0             #1: succeed
 * @retval      1             #2: input option is wrong or kind of input argument not specified
 * @retval      2             #3: argument has syntax error
 * @retval      3             #4: failed to move the job
 */
int
cmd_move_job(int argc, char **argv)
{
    int reqcode;
    if (0 == strcmp(argv[0], "top")) {
        reqcode = TO_TOP;
    } else if (0 == strcmp(argv[0], "bot")) {
        reqcode = TO_BOTTOM;
    } else {
        fprintf(stderr,  "Unknown subcmd <%s> specified for moving job.\n", argv[0]);
        exit(1);
    }

    while (TRUE) {
        int option_index = 0;
        static struct option long_options[] = {
            {"help", no_argument, 0, 'h'},
            {NULL, 0, 0, 0}
        };

        int opt;
        opt = getopt_long(argc, argv, "h", long_options, &option_index);
        if (-1 == opt) {
            break;
        }

        switch (opt) {
        case 'h':
            movejob_usage(argv[0]);
            exit(0);
        case '?':
        default:
            movejob_usage(argv[0]);
            exit(1);
        }
    }

    if (argc == optind) {
        fprintf(stderr, "Must specify a job ID.\n");
        movejob_usage(argv[0]);
        exit(1);
    }

    if (optind < argc-2) {
        fprintf(stderr, "Cannot specify more than one job ID.\n");
        movejob_usage(argv[0]);
        exit(1);
    }

    // get the job ID for moving its position.
    JOBID_T jobId = 0;
    if (get_one_jobid(argv[optind], &jobId)) {
        exit(2);
    }

    int position = 1;
    if (optind == argc - 2) {

	if (!isinteger(argv[++optind]) || atoi(argv[optind]) <= 0) {
            fprintf(stderr, "%s: Position value must be a positive integer.\n", argv[optind]);
            exit(2);
        }

	position = atoi(argv[optind]);
    }

    struct request moveRequest;
    moveRequest.number = 3;
    moveRequest.keyvalues = (struct keyvalue *)calloc(3, sizeof(struct keyvalue));
    if (NULL == moveRequest.keyvalues) {
        fprintf(stderr, "calloc(%ld) failed due to %m.\n",
                moveRequest.number*sizeof(struct keyvalue));
        exit(4);
    }

    moveRequest.keyvalues[0].key = REQUEST_KEY_REQUEST_CODE;
    moveRequest.keyvalues[0].value = (char *)calloc(12, sizeof(char));
    if (NULL == moveRequest.keyvalues[0].value) {
        fprintf(stderr, "calloc(%d) failed due to %m.\n", 12);
        exit(4);
    }
    snprintf(moveRequest.keyvalues[0].value, 12, "%d", reqcode);

    moveRequest.keyvalues[1].key = REQUEST_KEY_JOBIDS;
    moveRequest.keyvalues[1].value = (char *)calloc(23, sizeof(char));
    if (NULL == moveRequest.keyvalues[0].value) {
        fprintf(stderr, "calloc(%d) failed due to %m.\n", 23);
        exit(4);
    }
    snprintf(moveRequest.keyvalues[1].value, 12, "%lld", jobId);

    moveRequest.keyvalues[2].key = REQUEST_KEY_POSITION;
    moveRequest.keyvalues[2].value = (char *)calloc(12, sizeof(char));
    if (NULL == moveRequest.keyvalues[0].value) {
        fprintf(stderr, "calloc(%d) failed due to %m.\n", 12);
        exit(4);
    }
    snprintf(moveRequest.keyvalues[2].value, 12, "%d", position);

    int movedPos;
    movedPos = client_movejob(&moveRequest, NULL);
    if (0 > movedPos) {
        gf_xdr_free(gf_xdr_request, &moveRequest);
        exit(3);
    }
    gf_xdr_free(gf_xdr_request, &moveRequest);

    if (position != movedPos) {
	fprintf(stderr, "Warning: position value <%d> is beyond movable range.\n", position);
    }

    char strJobId[32];
    if (reqcode == TO_TOP) {
	fprintf(stdout, "Job <%s> has been moved to position %d from top.\n",
                jobid_2string(jobId, strJobId), movedPos);
    } else {
	fprintf(stdout, "Job <%s> has been moved to position %d from bottom.\n",
                jobid_2string(jobId, strJobId), movedPos);
    }

    exit(0);
} // end function cmd_move_job

static void
movejob_usage(const char *cmd)
{
    fprintf(stdout, "qp job %s usage: [-h, --help] jobId | \"jobId[index]\" [position]\n", cmd);

    return;
}
